#include "hoffmantreenode.h"
#include <QDebug>
#include <stdio.h>

HoffmanTreeNode::HoffmanTreeNode()
    : nodeName(""), weight(0),
      left(nullptr), right(nullptr)
{}

void HoffmanTreeNode::addLeft(HoffmanTreeNode* left)
{
    this->left = left;
}
void HoffmanTreeNode::addRight(HoffmanTreeNode *right)
{
    this->right = right;
}
QList<HoffmanTreeNode> HoffmanTreeNode::getAllSubNodes()
{
    QQueue<HoffmanTreeNode*> nodes;
    QList<HoffmanTreeNode> result;
    nodes.enqueue(this);
    while(nodes.size() > 0)
    {
        HoffmanTreeNode* elem = nodes.dequeue();
        result.append(*elem);
        if(elem->left)
            nodes.enqueue(elem->left);
        if(elem->right)
            nodes.append(elem->right);
    }
    return result;
}

int HoffmanTreeNode::getWeight() const
{
    return weight;
}

void HoffmanTreeNode::setWeight(int newWeight)
{
    weight = newWeight;
}
QString HoffmanTreeNode::nodeNames()
{
    QString res = "";
    for(auto& node : getAllSubNodes())
    {
        res += node.nodeName;
    }

    return res;
}
int HoffmanTreeNode::nodeWeightSum()
{
    int sum = 0;
    for(auto& node : getAllSubNodes())
    {
        sum += node.weight;
    }
    return sum;
}

QString HoffmanTreeNode::getNodeName() const
{
    return nodeName;
}

void HoffmanTreeNode::setNodeName(const QString &newNodeName)
{
    nodeName = newNodeName;
}
QList<HoffmanTreeNode*> HoffmanTreeByGoldfish::generateNodes(int argc,  char** argv)
{
    QList<HoffmanTreeNode*> nodes;
    int weight;
    for(int i = 0; i < argc; i++)
    {
        char* arg = argv[i];
        // qDebug() << arg << "\n";
        QString name = "";
        for(;; arg++)
        {
            char atIndex = *arg;
            if(atIndex == '=')
            {
                arg++;
                break;
            }
            if(atIndex == '\0')
            {
                argError(i, argv[i]);
            }
            name += atIndex;
        }

        if(sscanf(arg, "%i", &weight) != 1)
        {
            qDebug() << arg << " is not a number";
            exit(1);
        }
        HoffmanTreeNode* node = new HoffmanTreeNode();
        qDebug() << name << "->" << weight;
        node->setNodeName(name);
        node->setWeight(weight);
        nodes.append(node);
    }
    return nodes;
}
void HoffmanTreeByGoldfish::reduce(QList<HoffmanTreeNode*>& nodes)
{
    for(; nodes.size() > 1;)
    {
        int min = -1,  second_min = -1;
        for(int i = 0; i < nodes.size(); i++)
        {

            qDebug () << "i:" << i << "\tmin:" << min << "\tsec:" << second_min;
            if(min == -1 && second_min == -1)
            {
                qDebug() << "generating min";
                min = i;
                continue;
            }
            else if(second_min == -1)
            {
                qDebug() << "generating sec";
                if(min == -1)
                {
                    qDebug("no min to compare");
                    exit(1);
                }
                if(nodes[min]->nodeWeightSum()
                        <
                        nodes[i]->nodeWeightSum())
                {
                    second_min = i;
                }
                else
                {
                    second_min = min;
                    min = i;
                }
                continue;

            }
            /* now both min and secondMin have candidates
             * we need to decide where to put the new node
             */
            if(nodes[i]->nodeWeightSum() < nodes[min]->nodeWeightSum())
            {
                // nodes.remove(node);
                second_min = min;
                min = i;
            }
            else if(nodes[i]->nodeWeightSum() < nodes[second_min]->nodeWeightSum())
            {
                // nodes.remove(node);
                second_min = i;
            }
        }

        HoffmanTreeNode *merged = new HoffmanTreeNode();

        qDebug() << "<" << nodes[min]->nodeNames() << "->" << nodes[min]->nodeWeightSum();
        qDebug() << "<" << nodes[second_min]->nodeNames() << "->" << nodes[second_min]->nodeWeightSum();
        merged->addLeft(nodes[min]);
        merged->addRight(nodes[second_min]);
        nodes.remove(min);
        nodes.remove(second_min > min ? (second_min - 1) : second_min);
        nodes.append(merged);
    }
}
void HoffmanTreeByGoldfish::argError(int i, char* argv)
{
    qDebug() << "error: argument " << argv[i]
             << " (i.e. the " << i << "-th param )"
             << " is not in format <letter>=<digit>";
    exit(1);
}
